// Author: Staffan Persson
/*
* First of all, a big thanks to PhoneGap for providing the base for this code.
*/

// JSLint
/*jslint devel: true, browser: true */
// Assume ASOBAUDIO
/*globals ASOBAUDIO: false */

ASOBAUDIO.iOSBridge = ( function() {

	var bridgeElement, callbackIdCounter, callbacks, callbackStatus, commandQueue, runningCommands;

	/**
	 * Creates a bridge iframe used to notify the native code about queued
	 * commands.
	 */
	function createBridgeElement() {
		bridgeElement = document.createElement("iframe");
		bridgeElement.setAttribute("style", "display:none;");
		bridgeElement.setAttribute("height", "0px");
		bridgeElement.setAttribute("width", "0px");
		bridgeElement.setAttribute("frameborder", "0");
		document.documentElement.appendChild(bridgeElement);
		return bridgeElement;
	}

	/**
	 * Execute a command by queuing it and letting the native side know
	 * there are queued commands. The native side will then request all of the
	 * queued commands and execute them.
	 *
	 * The native side will call iOSBridge.callbackSuccess or
	 * iOSBridge.callbackError, depending upon the result of the action.
	 *
	 * @param {Function} successCallback The success callback
	 * @param {Function} failCallback The fail callback
	 * @param {String} service The name of the service to use
	 * @param {String[]} [args] Zero or more arguments to pass to the method
	 */
	function exec(successCallback, failCallback, service, args) {
		var callbackId, command, i;
		callbackId = null;

		// Start building the command object.
		command = {
			service : service,
			args : []
		};

		// Register the callbacks
		if(successCallback || failCallback) {
			callbackId = service + callbackId++;
			callbacks[callbackId] = {
				success : successCallback,
				fail : failCallback
			};
			command.args.push(callbackId);
		}

		// Register the arguments
		// Array check
		if(args && typeof args === 'object' && typeof args.length === 'number' && !(args.propertyIsEnumerable('length'))) {
			for( i = 0; i < args.length; i += 1) {
				command.args.push(args[i]);
			}
		}

		// Stringify and queue the command. We stringify to command now to
		// effectively clone the command arguments in case they are mutated before
		// the command is executed.
		commandQueue.push(JSON.stringify(command));

		// Inform the native layer that there are commands available.
		if(!runningCommands) {
			bridgeElement.src = "asobaudio://commands";
		}
	}

	function nativeLog(logMsg) {
		exec(null, null, "webLog", [logMsg]);
	}

	/**
	 * Called by native code to retrieve all queued commands and clear the queue.
	 */
	function getAndClearQueuedCommands() {
		var json = JSON.stringify(commandQueue);
		commandQueue = [];
		return json;
	}

	function init() {
		bridgeElement = createBridgeElement();
		// callbacks
		callbackIdCounter = 0;
		callbacks = {};
		callbackStatus = {
			NO_RESULT : 0,
			OK : 1,
			CLASS_NOT_FOUND_EXCEPTION : 2,
			ILLEGAL_ACCESS_EXCEPTION : 3,
			INSTANTIATION_EXCEPTION : 4,
			MALFORMED_URL_EXCEPTION : 5,
			IO_EXCEPTION : 6,
			INVALID_ACTION : 7,
			JSON_EXCEPTION : 8,
			ERROR : 9
		};
		// command queue
		commandQueue = [];
		runningCommands = false;

		// Redirect log
		console.log = nativeLog;
	}

	return {
		init : init,

		commandQueue : commandQueue,
		runningCommands : runningCommands,

		callbacks : callbacks,
		callbackStatus : callbackStatus,

		exec : exec,
		getAndClearQueuedCommands : getAndClearQueuedCommands,

		nativeLog : nativeLog
	};

}());

ASOBAUDIO.iOSBridge.init();
